本文基于hellowrold区块链环境,使用fabric-sdk-node 开发客户端应用。

1.新建连接文件

connection-org1.yaml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115

---
name: helloworld
version: 1.0.0
client:
organization: Org1
connection:
timeout:
peer:
endorser: '300'
organizations:
Org1:
mspid: Org1MSP
peers:
- peer0.org1.example.com
- peer1.org1.example.com
- peer2.org1.example.com
certificateAuthorities:
- ca.org1.example.com
peers:
peer0.org1.example.com:
url: grpcs://localhost:7051
tlsCACerts:
pem: |
-----BEGIN CERTIFICATE-----
MIICVzCCAf2gAwIBAgIQPpRrjZvaloVkj2FDjvjdHTAKBggqhkjOPQQDAjB2MQsw
CQYDVQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTEWMBQGA1UEBxMNU2FuIEZy
YW5jaXNjbzEZMBcGA1UEChMQb3JnMS5leGFtcGxlLmNvbTEfMB0GA1UEAxMWdGxz
Y2Eub3JnMS5leGFtcGxlLmNvbTAeFw0xOTEyMDYwNzE4MDBaFw0yOTEyMDMwNzE4
MDBaMHYxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpDYWxpZm9ybmlhMRYwFAYDVQQH
Ew1TYW4gRnJhbmNpc2NvMRkwFwYDVQQKExBvcmcxLmV4YW1wbGUuY29tMR8wHQYD
VQQDExZ0bHNjYS5vcmcxLmV4YW1wbGUuY29tMFkwEwYHKoZIzj0CAQYIKoZIzj0D
AQcDQgAEm6zQPRtevUHiMlaEfYaAK7Uu3yCbr7s/aoWtm6HqeSP0iKBb/VCXvV0j
LDgDLb1kK6obJBl8TA4SIX94xkQ+QaNtMGswDgYDVR0PAQH/BAQDAgGmMB0GA1Ud
JQQWMBQGCCsGAQUFBwMCBggrBgEFBQcDATAPBgNVHRMBAf8EBTADAQH/MCkGA1Ud
DgQiBCCaMWO9GF+XwAh3KmV1pJ8zmzqazuahyjDqymQPY79+YTAKBggqhkjOPQQD
AgNIADBFAiEAnpxtX/dFdqSZ34s6lETiMpNOg2Xus4z2X7MMHirNDvkCIHgmaZ54
B+c5lYRNqeiO9LSawwid4jfdbZvcNQ9QZQQH
-----END CERTIFICATE-----

grpcOptions:
ssl-target-name-override: peer0.org1.example.com
hostnameOverride: peer0.org1.example.com
peer1.org1.example.com:
url: grpcs://localhost:8051
tlsCACerts:
pem: |
-----BEGIN CERTIFICATE-----
MIICVzCCAf2gAwIBAgIQPpRrjZvaloVkj2FDjvjdHTAKBggqhkjOPQQDAjB2MQsw
CQYDVQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTEWMBQGA1UEBxMNU2FuIEZy
YW5jaXNjbzEZMBcGA1UEChMQb3JnMS5leGFtcGxlLmNvbTEfMB0GA1UEAxMWdGxz
Y2Eub3JnMS5leGFtcGxlLmNvbTAeFw0xOTEyMDYwNzE4MDBaFw0yOTEyMDMwNzE4
MDBaMHYxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpDYWxpZm9ybmlhMRYwFAYDVQQH
Ew1TYW4gRnJhbmNpc2NvMRkwFwYDVQQKExBvcmcxLmV4YW1wbGUuY29tMR8wHQYD
VQQDExZ0bHNjYS5vcmcxLmV4YW1wbGUuY29tMFkwEwYHKoZIzj0CAQYIKoZIzj0D
AQcDQgAEm6zQPRtevUHiMlaEfYaAK7Uu3yCbr7s/aoWtm6HqeSP0iKBb/VCXvV0j
LDgDLb1kK6obJBl8TA4SIX94xkQ+QaNtMGswDgYDVR0PAQH/BAQDAgGmMB0GA1Ud
JQQWMBQGCCsGAQUFBwMCBggrBgEFBQcDATAPBgNVHRMBAf8EBTADAQH/MCkGA1Ud
DgQiBCCaMWO9GF+XwAh3KmV1pJ8zmzqazuahyjDqymQPY79+YTAKBggqhkjOPQQD
AgNIADBFAiEAnpxtX/dFdqSZ34s6lETiMpNOg2Xus4z2X7MMHirNDvkCIHgmaZ54
B+c5lYRNqeiO9LSawwid4jfdbZvcNQ9QZQQH
-----END CERTIFICATE-----

grpcOptions:
ssl-target-name-override: peer1.org1.example.com
hostnameOverride: peer1.org1.example.com
peer2.org1.example.com:
url: grpcs://localhost:7251
tlsCACerts:
pem: |
-----BEGIN CERTIFICATE-----
MIICVzCCAf2gAwIBAgIQPpRrjZvaloVkj2FDjvjdHTAKBggqhkjOPQQDAjB2MQsw
CQYDVQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTEWMBQGA1UEBxMNU2FuIEZy
YW5jaXNjbzEZMBcGA1UEChMQb3JnMS5leGFtcGxlLmNvbTEfMB0GA1UEAxMWdGxz
Y2Eub3JnMS5leGFtcGxlLmNvbTAeFw0xOTEyMDYwNzE4MDBaFw0yOTEyMDMwNzE4
MDBaMHYxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpDYWxpZm9ybmlhMRYwFAYDVQQH
Ew1TYW4gRnJhbmNpc2NvMRkwFwYDVQQKExBvcmcxLmV4YW1wbGUuY29tMR8wHQYD
VQQDExZ0bHNjYS5vcmcxLmV4YW1wbGUuY29tMFkwEwYHKoZIzj0CAQYIKoZIzj0D
AQcDQgAEm6zQPRtevUHiMlaEfYaAK7Uu3yCbr7s/aoWtm6HqeSP0iKBb/VCXvV0j
LDgDLb1kK6obJBl8TA4SIX94xkQ+QaNtMGswDgYDVR0PAQH/BAQDAgGmMB0GA1Ud
JQQWMBQGCCsGAQUFBwMCBggrBgEFBQcDATAPBgNVHRMBAf8EBTADAQH/MCkGA1Ud
DgQiBCCaMWO9GF+XwAh3KmV1pJ8zmzqazuahyjDqymQPY79+YTAKBggqhkjOPQQD
AgNIADBFAiEAnpxtX/dFdqSZ34s6lETiMpNOg2Xus4z2X7MMHirNDvkCIHgmaZ54
B+c5lYRNqeiO9LSawwid4jfdbZvcNQ9QZQQH
-----END CERTIFICATE-----

grpcOptions:
ssl-target-name-override: peer2.org1.example.com
hostnameOverride: peer2.org1.example.com

certificateAuthorities:
ca.org1.example.com:
url: https://localhost:7054
caName: ca-org1
tlsCACerts:
pem: |
-----BEGIN CERTIFICATE-----
MIICUjCCAfigAwIBAgIRAMU4/9+dq0VuPKEjSFipx/AwCgYIKoZIzj0EAwIwczEL
MAkGA1UEBhMCVVMxEzARBgNVBAgTCkNhbGlmb3JuaWExFjAUBgNVBAcTDVNhbiBG
cmFuY2lzY28xGTAXBgNVBAoTEG9yZzEuZXhhbXBsZS5jb20xHDAaBgNVBAMTE2Nh
Lm9yZzEuZXhhbXBsZS5jb20wHhcNMTkxMjA2MDcxODAwWhcNMjkxMjAzMDcxODAw
WjBzMQswCQYDVQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTEWMBQGA1UEBxMN
U2FuIEZyYW5jaXNjbzEZMBcGA1UEChMQb3JnMS5leGFtcGxlLmNvbTEcMBoGA1UE
AxMTY2Eub3JnMS5leGFtcGxlLmNvbTBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IA
BHkedN9y3BKwEyYKqcWM+AkWO5/xwnmybQ+eT4US8MZWNRqPpbxj04QaIb38WLaZ
EEHWpwCZ5ibI7pMBL6pQt7qjbTBrMA4GA1UdDwEB/wQEAwIBpjAdBgNVHSUEFjAU
BggrBgEFBQcDAgYIKwYBBQUHAwEwDwYDVR0TAQH/BAUwAwEB/zApBgNVHQ4EIgQg
KmZ7N0Vi4BkkiDL1YbHbv8hdIH4v1feKEDrrPbxEORswCgYIKoZIzj0EAwIDSAAw
RQIhAIdEP0JbQI8LqW4XJ6fI/jmS9gqQPtGcwJxtof6pEieCAiAHxiG/VINKnQkT
18juN4fAU6fKQKbRad4/WA5wA4Z6Jw==
-----END CERTIFICATE-----


httpOptions:
verify: false

2.nodejs 脚本

在helloworld下创建script目录,用于放js文件

2.1 enrollAdmin.js

用于从 CA服务中获取 admin 用户注册信息

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
/*
* SPDX-License-Identifier: Apache-2.0
*/

'use strict';

const FabricCAServices = require('fabric-ca-client');
const { FileSystemWallet, X509WalletMixin } = require('fabric-network');
const fs = require('fs');
const path = require('path');

const ccpPath = path.resolve(__dirname, '..', '..', 'connection-org1.yaml');
const ccpJSON = fs.readFileSync(ccpPath, 'utf8');
const ccp = JSON.parse(ccpJSON);

async function main() {
try {

// Create a new CA client for interacting with the CA.
const caInfo = ccp.certificateAuthorities['ca.org1.example.com'];
const caTLSCACerts = caInfo.tlsCACerts.pem;
const ca = new FabricCAServices(caInfo.url, { trustedRoots: caTLSCACerts, verify: false }, caInfo.caName);

// Create a new file system based wallet for managing identities.
const walletPath = path.join(process.cwd(), 'wallet');
const wallet = new FileSystemWallet(walletPath);
console.log(`Wallet path: ${walletPath}`);

// Check to see if we've already enrolled the admin user.
const adminExists = await wallet.exists('admin');
if (adminExists) {
console.log('An identity for the admin user "admin" already exists in the wallet');
return;
}

// Enroll the admin user, and import the new identity into the wallet.
const enrollment = await ca.enroll({ enrollmentID: 'admin', enrollmentSecret: 'adminpw' });
const identity = X509WalletMixin.createIdentity('Org1MSP', enrollment.certificate, enrollment.key.toBytes());
await wallet.import('admin', identity);
console.log('Successfully enrolled admin user "admin" and imported it into the wallet');

} catch (error) {
console.error(`Failed to enroll admin user "admin": ${error}`);
process.exit(1);
}
}

main();

2.2 registerUser.js

用于注册用户user1

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57

/*
* SPDX-License-Identifier: Apache-2.0
*/

'use strict';

const { FileSystemWallet, Gateway, X509WalletMixin } = require('fabric-network');
const path = require('path');

const ccpPath = path.resolve(__dirname, '..', '..', 'connection-org1.yaml');

async function main() {
try {

// Create a new file system based wallet for managing identities.
const walletPath = path.join(process.cwd(), 'wallet');
const wallet = new FileSystemWallet(walletPath);
console.log(`Wallet path: ${walletPath}`);

// Check to see if we've already enrolled the user.
const userExists = await wallet.exists('user1');
if (userExists) {
console.log('An identity for the user "user1" already exists in the wallet');
return;
}

// Check to see if we've already enrolled the admin user.
const adminExists = await wallet.exists('admin');
if (!adminExists) {
console.log('An identity for the admin user "admin" does not exist in the wallet');
console.log('Run the enrollAdmin.js application before retrying');
return;
}

// Create a new gateway for connecting to our peer node.
const gateway = new Gateway();
await gateway.connect(ccpPath, { wallet, identity: 'admin', discovery: { enabled: true, asLocalhost: true } });

// Get the CA client object from the gateway for interacting with the CA.
const ca = gateway.getClient().getCertificateAuthority();
const adminIdentity = gateway.getCurrentIdentity();

// Register the user, enroll the user, and import the new identity into the wallet.
const secret = await ca.register({ affiliation: 'org1.department1', enrollmentID: 'user1', role: 'client' }, adminIdentity);
const enrollment = await ca.enroll({ enrollmentID: 'user1', enrollmentSecret: secret });
const userIdentity = X509WalletMixin.createIdentity('Org1MSP', enrollment.certificate, enrollment.key.toBytes());
await wallet.import('user1', userIdentity);
console.log('Successfully registered and enrolled admin user "user1" and imported it into the wallet');

} catch (error) {
console.error(`Failed to register user "user1": ${error}`);
process.exit(1);
}
}

main();

2.3 query.js

链码查询

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52

/*
* SPDX-License-Identifier: Apache-2.0
*/

'use strict';

const { FileSystemWallet, Gateway } = require('fabric-network');
const path = require('path');

const ccpPath = path.resolve(__dirname, '..', '..', 'connection-org1.yaml');

async function main() {
try {

// Create a new file system based wallet for managing identities.
const walletPath = path.join(process.cwd(), 'wallet');
const wallet = new FileSystemWallet(walletPath);
console.log(`Wallet path: ${walletPath}`);

// Check to see if we've already enrolled the user.
const userExists = await wallet.exists('admin');
if (!userExists) {
console.log('An identity for the user "user1" does not exist in the wallet');
console.log('Run the registerUser.js application before retrying');
return;
}

// Create a new gateway for connecting to our peer node.
const gateway = new Gateway();
await gateway.connect(ccpPath, { wallet, identity: 'admin', discovery: { enabled: true, asLocalhost: true } });
console.log('11111')

// Get the network (channel) our contract is deployed to.
const network = await gateway.getNetwork('mychannel');
console.log('22222')
// Get the contract from the network.
const contract = network.getContract('mycc');
console.log('3333')
// Evaluate the specified transaction.
// queryCar transaction - requires 1 argument, ex: ('queryCar', 'CAR4')
// queryAllCars transaction - requires no arguments, ex: ('queryAllCars')
const result = await contract.evaluateTransaction('get','a');
console.log(`Transaction has been evaluated, result is: ${result.toString()}`);

} catch (error) {
console.error(`Failed to evaluate transaction: ${error}`);
process.exit(1);
}
}

main();

2.4 invoke.js

执行链码方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
/*
* SPDX-License-Identifier: Apache-2.0
*/

'use strict';

const { FileSystemWallet, Gateway } = require('fabric-network');
const path = require('path');

const ccpPath = path.resolve(__dirname, '..', '..', 'connection-org1.yaml');

async function main() {
try {

// Create a new file system based wallet for managing identities.
const walletPath = path.join(process.cwd(), 'wallet');
const wallet = new FileSystemWallet(walletPath);
console.log(`Wallet path: ${walletPath}`);

// Check to see if we've already enrolled the user.
const userExists = await wallet.exists('user1');
if (!userExists) {
console.log('An identity for the user "user1" does not exist in the wallet');
console.log('Run the registerUser.js application before retrying');
return;
}

// Create a new gateway for connecting to our peer node.
const gateway = new Gateway();
await gateway.connect(ccpPath, { wallet, identity: 'user1', discovery: { enabled: true, asLocalhost: true } });

// Get the network (channel) our contract is deployed to.
const network = await gateway.getNetwork('mychannel');

// Get the contract from the network.
const contract = network.getContract('mycc');

// Submit the specified transaction.
// createCar transaction - requires 5 argument, ex: ('createCar', 'CAR12', 'Honda', 'Accord', 'Black', 'Tom')
// changeCarOwner transaction - requires 2 args , ex: ('changeCarOwner', 'CAR10', 'Dave')
await contract.submitTransaction('set', 'a', 'hello china');
console.log('Transaction has been submitted');

// Disconnect from the gateway.
await gateway.disconnect();

} catch (error) {
console.error(`Failed to submit transaction: ${error}`);
process.exit(1);
}
}

main();

2.5 安装Node依赖

1
2
#进入script目录
node install

##2.6执行调用链码

1
2
3
4
5
6
7
8
9
10
11
12
#获取admin用户证书
node enrollAdmin.js
#注册用户user1
node registerUser.js

#查询链码
node query.js
#执行链码set
node invoke.js

#查看调用set后的结果
node query.js